/***************************************** 
 * Desc: UGUI通用抽象UI基类
*****************************************/

using System;
using System.Collections.Generic;
using UnityEngine;

namespace Common.UGUI.Base {

    /// <summary>
    /// 播放UI动画的委托
    /// </summary>
    /// <param name="onSucc">播放成功回调</param>
    /// <param name="onFail">播放失败回调</param>
    /// <param name="onFinished">播放完成回调</param>
    public delegate void PlayUIAnimate(Action onSucc, Action<string> onFail, Action onFinished);
    /// <summary>
    /// 停止UI动画的委托
    /// </summary>
    /// <param name="onSucc">播放成功回调</param>
    /// <param name="onFail">播放失败回调</param>
    public delegate void StopUIAnimate(Action onSucc, Action<string> onFail);

    [ExecuteInEditMode]
    [DisallowMultipleComponent]
    [RequireComponent(typeof(RectTransform))]
    public class UGUIView : MonoBehaviour {

    #region 域

        /// <summary>
        /// 是否激活
        /// </summary>
        public virtual bool IsActive { 
            
            get {
                return _isActive;
            } 
            
            protected set {
                SetActive(value);
            }
        }

        /// <summary>
        /// 本地层级，当然直接SetSiblingIndex调用也可以，
        /// 不过很可能出BUG，不能直接将这个值等价于SiblingIndex
        /// </summary>
        public int SortingOrder { 
            get {
                return _sortingOrder;
            }
            set {
                _sortingOrder = value;
            } 
        }

        /// <summary>
        /// UI名字
        /// </summary>
        public string Name { 
            get {
                return _name;
            }
            set {
                SetName(value);
            }
        }

        /// <summary>
        /// 父视图
        /// </summary>
        public UGUIView Parent { get { return _parent; } }

        /// <summary>
        /// 子视图(一定可以返回一个不为空的List)
        /// </summary>
        public HashSet<UGUIView> Children {

            get {

                if (_children == null) {
                    _children = new HashSet<UGUIView>();
                }

                return _children;
            }
        }

        /// <summary>
        /// 必定获取对象GameObject
        /// </summary>
        public GameObject GameObject {

            get {

                if (_gameObject == null && null != this) {

                    _gameObject = gameObject;
                }

                return _gameObject;
            }
        }

        /// <summary>
        /// 必定获取对象Transform
        /// </summary>
        public Transform Transform {

            get {

                if (_transform == null) {

                    _transform = GameObject.transform;
                }

                return _transform;
            }
        }

        /// <summary>
        /// 必定获取对象RectTransform
        /// </summary>
        public RectTransform RectTransform {

            get {

                if(_rectTransform == null) {

                    _rectTransform = (RectTransform)Transform;
                }

                return _rectTransform;
            }
        }

        /// <summary>
        /// 当View激活时的回调
        /// </summary>
        public Action OnEnable { get; set; }

        /// <summary>
        /// 当View隐藏时的回调
        /// </summary>
        public Action OnDisable { get; set; }

        protected UGUIView _parent = null;

        [SerializeField]
        protected bool _isActive = true;
        [SerializeField]
        private int _sortingOrder = 0;
        [SerializeField]
        protected string _name = "Unknown";

        // 判断是否使用过Destroy函数进行销毁
        private GameObject _gameObject = null;
        private Transform _transform = null;
        private RectTransform _rectTransform = null;
        private HashSet<UGUIView> _children = new HashSet<UGUIView>();

        private Dictionary<string, PlayUIAnimate> _playAnimFunctionDict = new Dictionary<string, PlayUIAnimate>();
        private Dictionary<string, StopUIAnimate> _stopAnimFunctionDict = new Dictionary<string, StopUIAnimate>();

    #endregion

    #region Unity生命周期

        private void Awake() {

            _gameObject = gameObject;
            _transform = _gameObject.transform;
            _rectTransform = (RectTransform)_transform;

            OnEnable = null;
            OnDisable = null;

            if(string.Compare(_name,"Unknown") == 0) {
                _name = _gameObject.name;
            }

            SetName(_name);

            OnAwake();
        }

        private void Start() {

            AutoFindParent(true);

            OnStart();
        }

        /// <summary>
        /// 注意不要再操作任何和GameObject和Transform相关了
        /// </summary>
        private void OnDestroy() {

            //if (UGUIManager.Instance.IfHasUGUIView(Name, GetType())) {

            //    UGUIManager.Instance.RemoveUGUIView(this, GetType());
            //}

            if (_parent != null) {

                if (_parent.Children.Contains(this)) {

                    _parent.Children.Remove(this);
                }
            }

            OnDestroyByMono();
        }

    #endregion

    #region 动画相关

        #region 注册动画

        /// <summary>
        /// 根据动画名注册一个播放UI动画函数
        /// </summary>
        /// <param name="animName">动画名</param>
        /// <param name="function">动画函数</param>
        /// <param name="ifReplace">是否强制替换</param>
        public void RegisterPlayUIAnimate(string animName, PlayUIAnimate function, bool ifReplace = false) {

            if(function == null) {

                Debug.LogError("UGUI name " + Name + " RegisterPlayUIAnimate failed, input function can't be null with name: " + animName);

                return;
            }

            if (!_playAnimFunctionDict.ContainsKey(animName)) {

                _playAnimFunctionDict.Add(animName, function);

            } else if (ifReplace) {

                _playAnimFunctionDict[animName] = function;
            } else {

                Debug.LogError("UGUI name " + Name + " RegisterPlayUIAnimate failed, already has UI animate with name: " + animName);
            }
        }

        /// <summary>
        /// 根据动画名移除一个播放UI动画函数
        /// </summary>
        /// <param name="animName">动画名</param>
        public void RemovePlayUIAnimate(string animName) {

            if (_playAnimFunctionDict.ContainsKey(animName)) {

                _playAnimFunctionDict.Remove(animName);

            } else {

                Debug.LogError("UGUI name " + Name + " RemovePlayUIAnimate failed, no animate named " + animName);
            }
        }

        /// <summary>
        /// 根据动画名注册一个停止UI动画函数
        /// </summary>
        /// <param name="animName">动画名</param>
        /// <param name="function">停止UI动画函数</param>
        /// <param name="ifReplace">是否强制替换</param>
        public void RegisterStopUIAnimate(string animName, StopUIAnimate function, bool ifReplace = false) {

            if (function == null) {

                Debug.LogError("UGUI name " + Name + " RegisterStopUIAnimate failed, input function can't be null with name: " + animName);

                return;
            }

            if (!_stopAnimFunctionDict.ContainsKey(animName)) {

                _stopAnimFunctionDict.Add(animName, function);

            } else if (ifReplace) {

                _stopAnimFunctionDict[animName] = function;
            } else {

                Debug.LogError("UGUI name " + Name + " RegisterStopUIAnimate failed, already has UI animate with name: " + animName);
            }
        }

        /// <summary>
        /// 根据动画名移除一个停止UI动画函数
        /// </summary>
        /// <param name="animName">动画名</param>
        public void RemoveStopUIAnimate(string animName) {

            if (_stopAnimFunctionDict.ContainsKey(animName)) {

                _stopAnimFunctionDict.Remove(animName);

            } else {

                Debug.LogError("UGUI name " + Name + " RemoveStopUIAnimate failed, no animate named " + animName);
            }
        }

        #endregion

        #region 操作动画

        /// <summary>
        /// 根据UI动画名播放一个UI动画
        /// </summary>
        /// <param name="animName">UI动画名</param>
        /// <param name="onSucc">成功回调</param>
        /// <param name="onFailed">失败回调</param>
        /// <param name="onFinished">播放完成回调</param>
        public void PlayUIAnimateByName(string animName, Action onSucc, Action<string> onFailed, Action onFinished) {

            if (_playAnimFunctionDict.ContainsKey(animName)) {

                _playAnimFunctionDict[animName](onSucc, onFailed, onFinished);
            } else {

                Debug.LogError("UGUI name " + Name + " PlayUIAnimateByName failed, no animate named " + animName);
            }
        }

        /// <summary>
        /// 根据UI动画名停止一个UI动画
        /// </summary>
        /// <param name="animName">UI动画名</param>
        /// <param name="onSucc">成功回调</param>
        /// <param name="onFailed">失败回调</param>
        public void StopUIAnimateByName(string animName, Action onSucc, Action<string> onFailed) {

            if (_stopAnimFunctionDict.ContainsKey(animName)) {

                _stopAnimFunctionDict[animName](onSucc, onFailed);
            } else {

                Debug.LogError("UGUI name " + Name + " StopUIAnimateByName failed, no animate named " + animName);
            }
        }

        #endregion

    #endregion

        #region 通用UI操作

        /// <summary>
        /// 设置UI名字
        /// </summary>
        public virtual void SetName(string name) {

            if (name != null) {

                //UGUIManager manager = UGUIManager.Instance;

                //if (manager.IfHasUGUIView(Name, GetType())) {

                //    manager.RemoveUGUIView(this, GetType());
                //}

                _name = name;

               // manager.RegisterUGUIView(this, GetType());

                GameObject.name = Name;
            }
        }

#if UNITY_EDITOR
        /// <summary>
        /// 编辑器用代码，正常流程中用SetName
        /// </summary>
        public virtual void SetEditorName(string name) {

            if (name != null) {

                _name = name;

                GameObject.name = Name;
            }
        }
#endif

        /// <summary>
        /// 设置是否激活
        /// </summary>
        public virtual void SetActive(bool isActive) {

            _isActive = isActive;

            if (isActive) {

                if(OnEnable != null) {
                
                    OnEnable();
                }
            } else {
                
                if(OnDisable != null) {
                
                    OnDisable();
                }
            }

            if (GameObject != null)
                GameObject.SetActive(_isActive);
        }

        /// <summary>
        /// 用缩放控制Active
        /// </summary>
        public void SetActiveByScale(bool isActive) {

            _isActive = isActive;

            if (isActive) {

                if (OnEnable != null) {

                    OnEnable();
                }

                RectTransform.localScale = Vector3.one;
            } else {

                if (OnDisable != null) {

                    OnDisable();
                }

                RectTransform.localScale = Vector3.zero;
            }
        }

        /// <summary>
        /// 设置父对象
        /// </summary>
        public virtual void SetParent(UGUIView parent, bool ifRemoveFromParent = true) {

            // 移除旧的父视图
            if (_parent != null) {

                if (_parent.Children.Count > 0) {

                    if (ifRemoveFromParent) {

                        if (!_parent.Children.Remove(this)) {

                            if (parent != null) {
                                Debug.LogError("SetParent Error: " + Name + " try set parent 2 " + parent.Name +
                                    " but old parent: " + _parent.Name + " didn't find this child.");
                            } else {
                                Debug.LogError("SetParent Error: " + Name + " try set parent 2 null  but old parent: " + _parent.Name + " didn't find this child.");
                            }
                        }
                    }
                } else {

                    if (parent != null) {
                        
                        Debug.LogError("SetParent Error: " + Name + " try set parent 2 " + parent.Name +
                            " but old parent: " + _parent.Name + " child length is zero.");
                    } else {

                        Debug.LogError("SetParent Error: " + Name + " try set parent 2 null but old parent: " + _parent.Name + " child length is zero.");
                    }
                }
            }

            if (parent == null) {

                Transform.SetParent(null,false);

                _parent = null;
            } else {

                // 添加至新的父视图
                if (parent.AddChild(this)) {

                    Transform.SetParent(parent.Transform, false);

                    _parent = parent;
                }
            }
        }

        /// <summary>
        /// 添加子对象（子类覆盖，对于子类有可能要做特殊的类型检查）
        /// </summary>
        protected virtual bool AddChild(UGUIView child) {

            if (!Children.Contains(this)) {

                Children.Add(child);

                return true;

            } else {

                Debug.LogError("AddChildren Error: try AddChildren child " + child.Name +
                        " but " + Name + " already has this UGUIView.");

                return false;
            }
        }

        /// <summary>
        /// 用于子对象排序
        /// </summary>
        private struct SortChildData {

            public int SortingOrder;

            public Transform TargetChild;

            public SortChildData(int sortingData, Transform targetChild) {

                SortingOrder = sortingData;

                TargetChild = targetChild;
            }
        }

        /// <summary>
        /// 根据SortingOrder的值对同级的所有GameObject对象进行排序
        /// </summary>
        public virtual void SortGameObjectBySortingOrder() {

            if (_parent != null) {

                Transform parent = Transform.parent;

                int childCount = parent.childCount;

                SortChildData[] children = new SortChildData[childCount];

                UGUIView childView = null;

                for (int i = 0; i < childCount; ++i) {

                    Transform child = parent.GetChild(i);

                    childView = child.GetComponent<UGUIView>();

                    if (childView != null) {

                        children[i] = new SortChildData(childView.SortingOrder, child);
                    } else {

                        children[i] = new SortChildData(i, child);
                    }
                }

                Array.Sort(children, (a, b) => {

                    return a.SortingOrder - b.SortingOrder;
                });

                // 先全部移除
                foreach (SortChildData child in children) {

                    child.TargetChild.SetParent(null, false);
                }

                // 再重新按照顺序录入
                foreach (SortChildData child in children) {

                    child.TargetChild.SetParent(parent, false);
                }
            }
        }

        /// <summary>
        /// 销毁当前UI
        /// </summary>
        public void Destroy(bool ifRemoveRromUGUIManagerNow = true) {

            if (ifRemoveRromUGUIManagerNow) {

                //if (UGUIManager.Instance.IfHasUGUIView(Name, GetType())) {

                //    UGUIManager.Instance.RemoveUGUIView(this, GetType());
                //}
            }

            // 先设置为不可操作，因为不一定立刻就被Unity销毁
            SetActive(false);

            if(_parent != null) {

                if (_parent.Children.Contains(this)) {

                    _parent.Children.Remove(this);
                }
            }

            if (GameObject != null) {

                GameObject.Destroy(GameObject);
            }
        }

    #endregion

    #region 继承的生命周期操作

        /// <summary>
        /// 子类如有需要覆盖，在Mono的Awake最后调用
        /// </summary>
        protected virtual void OnAwake() {

        }

        /// <summary>
        /// 子类如有需要覆盖，在Mono的Start最后调用
        /// </summary>
        protected virtual void OnStart() {

        }

        /// <summary>
        /// 子类如有需要覆盖，在Mono的OnDestroy最先调用
        /// </summary>
        protected virtual void OnDestroyByMono() {

        }

        #endregion

        #region 结构用函数

        /// <summary>
        /// 自动获取当前树结构下的父节点
        /// </summary>
        public virtual void AutoFindParent(bool ifForceFind = false) {

            if (_parent == null || ifForceFind) {

                Transform parent = Transform.parent;

                UGUIView parentView = null;

                while (parent != null) {

                    parentView = parent.GetComponent<UGUIView>();

                    if (parentView != null) {

                        if (parentView.AddChild(this)) {

                            //Unity编辑器中可能手动操作会导致这种情况所以不报错了，需要检测就注释掉宏编译
#if !UNITY_EDITOR
                            if (_parent != parentView) {
                                if (_parent != null) {
                                    Debug.LogError("Old parent: " + _parent.Name + " is not equal to parent: " + parentView.Name + " now.");
                                }
                            }
#endif

                            _parent = parentView;
                        }

                        break;

                    } else {

                        parent = parent.parent;
                    }
                }


                if (_parent == null) {
#if !UNITY_EDITOR
                    Debug.LogError("UGUIView: " + GetType().Name + " can't exsit without parent.");
#else
                    Debug.Log("UGUIView: " + GetType().Name + " can't exsit without parent.");
#endif
                }
            }
    #endregion
        }
    }
}
